package cn.tedu.charging.order.advice;

import cn.tedu.charging.common.pojo.message.ChargingCheckResultMessage;
import cn.tedu.charging.common.pojo.message.DelayCheckMessage;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

//@Aspect
@Component
@Slf4j
public class RedisLockAspect {
    @Autowired
    private RedisTemplate redisTemplate;
    //切入consumerService
    @Pointcut("execution(* cn.tedu.charging.order.service.ConsumerService.*(..))")
    public void consumerPoint(){};
    @Around("consumerPoint()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        //获取方法参数 一个参数 DelayCheckMessage ChargingCheckResultMessage
        Object[] args = joinPoint.getArgs();//2个类型 一个元素
        String orderNo="";
        //args循环遍历 拿到orderNo
        for (Object arg : args) {
            //DelayCheck checkResult
            if (arg instanceof DelayCheckMessage){
                orderNo=((DelayCheckMessage) arg).getOrderNo();
            }else if (arg instanceof ChargingCheckResultMessage){
                orderNo=((ChargingCheckResultMessage)arg).getOrderNo();
            }
        }
        if (orderNo.equals("")){
            System.out.println("入参有问题 切面有问题");
            return joinPoint.proceed();
        }
        //1.抢锁
        String lockKey="charging:order:lock:"+orderNo;
        ValueOperations stringOps = redisTemplate.opsForValue();
        //2.setnx 5秒自动超时时间
        boolean haveLock=false;
        int count=0;
        try{
            do{
                count++;//第一次抢 count==1 2 3 4 第四次最高了
                if (count>1&&count<=4){
                    //不是第一次抢
                    Thread.sleep(1000);
                }else if(count>4){
                    //5,6,7不让抢 消费结束了
                    return null;
                }
                haveLock=stringOps.setIfAbsent(lockKey,"",5, TimeUnit.SECONDS);
            }while (!haveLock);
            //调用业务代码 处理业务逻辑
            return joinPoint.proceed();//目标方法执行 核心业务
            //业务处理完毕之后,手动确认反馈
        }catch (Exception e){
            System.out.println("执行环绕 目标方法抢锁失败");
        }finally {
            //2.释放
            redisTemplate.delete(lockKey);
        }
        return null;

    }
}
